<?php
/*
 * kernel/object.file.php 
 * 
 * Files and directories
 * 
 * Copyright (C) 2010, Taras Kudla
 * 
 */
define("_FILENAME_SIZE",30);
final class file extends kernel {
	
    private $filestable = "files";
    
    public function init(){
    	
	}

	private function encodefilename($name){
		$val = rand(30, 100);
		$name = preg_replace("/[^A-z0-9_]/","",$name);
		$name = $val.substr($name,0,15).md5($name.microtime());
		$name = substr($name,0,_FILENAME_SIZE);
		return $name;
	}

	public function resizeimage($id, $width, $height = null){
		# id - image file id, if height == null ,uses aspect ratio to height
		$_    = $this->filenamebyid($id);
		$__   = $this->parseextension($_);
		$name = crc32(md5($_) . microtime());
		$__   = strtolower($__);
		if ($__ == "jpg" || $__ == "jpeg"){
			$im = imagecreatefromjpeg($this->core->parseasdir($this->core->get("uploadsdir")).$_);
		}
		if ($__ == "png"){
			$im = imagecreatefromstring(file_get_contents($this->core->parseasdir($this->core->get("uploadsdir")). $_));
			imagealphablending($im, true);
			imagesavealpha($im, true);
		}
		if ($__ == "gif"){
			$im = imagecreatefromgif($this->core->parseasdir($this->core->get("uploadsdir")). $_);
			imagealphablending($im, true);
			imagesavealpha($im, true);
		}
		if (!$im){
			$this->core->error("file","Error in image resizing. Cannot create image from file.");
			return false;
		}
		$x = imagesx($im);
		$y = imagesy($im);
		$w = null;
		$h = null;
		if ($x < $width && $width != null)
			return true;
		if ($y < $height && $height != null && $width == null)
			return true;
		if ($height == null){
			$w = $width;
			$h = round(($y / $x) * $w);
		}else{
			$w = $width;
			$h = $height;
		}
		if ($width == null && $height != null){
			$w = round(($x / $y) * $h);
			$h = $height;
		}
		$tmp = imagecreatetruecolor($w, $h);
		imagecopyresampled($tmp, $im, 0, 0, 0, 0, round($w), round($h), $x, $y);
		if ($__ == "jpg" || $__ == "jpeg")
			$t = @imagejpeg($tmp, $this->core->parseasdir($this->core->get("uploadsdir")). $_, 100);
		if ($__ == "png")
			$t = @imagepng($tmp, $this->core->parseasdir($this->core->get("uploadsdir")). $_);
		if ($__ == "gif")
			$t = @imagegif($tmp, $this->core->parseasdir($this->core->get("uploadsdir")). $_);
		imagedestroy($im);
		imagedestroy($tmp);
		if (!$t){
			$this->core->error("file","Error in image resizing");
			return false;
		}
		# saving data in db
		$size = filesize($this->core->parseasdir($this->core->get("uploadsdir")). $_);
		$this->core->dbo->update($this->filestable, "set size='" . (int) $size . "' where id='" . (int) $id . "' ");
		return $id;
	}
	
	public function getfileurl($name){
		# checking if id 
		if( is_numeric($name)){
			$name = $this->filenamebyid($name);
		}
		if( !$name)
			return false;
		return $this->core->parseasurl($this->core->get("uploadsurl")).$name;
	}
	
	public function copysysfile($id){
		$n       = $this->filenamebyid($id);
		$newname = $this->encodefilename($n). "." . $this->parseextension($n);
		$type    = null;
		$size    = null;
		$c       = @copy($this->core->parseasdir($this->core->get("uploadsdir")). $n, $this->core->parseasdir($this->core->get("uploadsdir")). $newname);
		if ($c){
			$file = $this->insertfiledata($newname, $type, $size);
		if (is_numeric($file))
			return $file;
		}
		$this->core->error("file","cannot copy file");
		return false;
	}
	
	# checking if file is image
	public function is_image($filename){
		$mime = $this->getmimetype($filename);
		$array = explode("/",$mime);
		return ($array[0]=="image")?true:false;
	}
	# getting file mimetype
	public function getmimetype($filename){
		/**
		 * some of code of this method was copied from php.net
		 * http://us2.php.net/manual/en/function.mime-content-type.php#87856
		 */
		if( function_exists("mime_content_type")){
			return mime_content_type($filename);
		}
		$mime_types = array(
			'txt' => 'text/plain',
			'htm' => 'text/html',
			'html' => 'text/html',
			'php' => 'text/html',
			'css' => 'text/css',
			'js' => 'application/javascript',
			'json' => 'application/json',
			'xml' => 'application/xml',
			'swf' => 'application/x-shockwave-flash',
			'flv' => 'video/x-flv',
			# images
			'png' => 'image/png',
			'jpe' => 'image/jpeg',
			'jpeg' => 'image/jpeg',
			'jpg' => 'image/jpeg',
			'gif' => 'image/gif',
			'bmp' => 'image/bmp',
			'ico' => 'image/vnd.microsoft.icon',
			'tiff' => 'image/tiff',
			'tif' => 'image/tiff',
			'svg' => 'image/svg+xml',
			'svgz' => 'image/svg+xml',
			# archives
			'zip' => 'application/zip',
			'rar' => 'application/x-rar-compressed',
			'exe' => 'application/x-msdownload',
			'msi' => 'application/x-msdownload',
			'cab' => 'application/vnd.ms-cab-compressed',
			# audio/video
			'mp3' => 'audio/mpeg',
			'qt' => 'video/quicktime',
			'mov' => 'video/quicktime',
			# adobe
			'pdf' => 'application/pdf',
			'psd' => 'image/vnd.adobe.photoshop',
			'ai' => 'application/postscript',
			'eps' => 'application/postscript',
			'ps' => 'application/postscript',
			# ms office
			'doc' => 'application/msword',
			'docx' => 'application/msword',
			'rtf' => 'application/rtf',
			'xls' => 'application/vnd.ms-excel',
			'ppt' => 'application/vnd.ms-powerpoint',
			# open office
			'odt' => 'application/vnd.oasis.opendocument.text',
			'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
		);
		$ext = strtolower(array_pop(explode('.',$filename)));
		if (array_key_exists($ext, $mime_types)) {
			return $mime_types[$ext];
		} elseif (function_exists('finfo_open')) {
			$finfo = finfo_open(FILEINFO_MIME);
			$mimetype = finfo_file($finfo, $filename);
			finfo_close($finfo);
			return $mimetype;
		} else {
			return 'unknown/'.(strlen($ext)>4?"unknown":$ext);
		}
	}
	
	# move uploaded file to uploads directory
	public function copyuploadedfile($area, $exts = null){
		if (!isset($_FILES[$area])){
			return false;
		}
		$name  = $_FILES[$area]["name"];
		$type  = $_FILES[$area]["type"];
		$size  = $_FILES[$area]["size"];
		$tname = $_FILES[$area]["tmp_name"];
		$ext   = $this->parseextension($name);
		if (is_array($exts) && !in_array(strtolower($ext), $exts)){
			$this->core->error("file","file type is not supported");
			return false;
		}
		$ext = strtolower($ext);
		if ($this->is_image($name) && !getimagesize($tname)){
			return false;
		}
		$rname = $this->encodefilename($name . rand(100, 999)) . ($ext != null ? (($ext == 'php' || $ext == 'phtml' || $ext == 'htm' || $ext == 'html' || $ext == 'xml') ? ".txt" : "." . $ext) : null);
		$_ = copy($tname, $this->core->parseasdir($this->core->get("uploadsdir")). $rname);
		if ($_){
			$file = $this->insertfiledata($rname, $type, $size);
		}else{
			return false;
		}
		# resize, if file is image
		if ($this->is_image($name)){
			list($width, $height, $type, $attr) = getimagesize($this->core->parseasdir($this->core->get("uploadsdir")). $rname);
			$this->resizeimage($file, $width - 1, $height - 1);
		}
		return $file;
	}
	# bind all file information to system files database
	public function bindfile($filename){
		if( file_exists($filename)){
			$this->core->error("file","Cannot bind file to system database, file '$filename' not found");
			return false;
		}
		$type = $this->getmimetype($filename);
		preg_match("/^.+([^\/\\\]+)$/U",$filename,$tmp);
		$name = $tmp[1];
		$size = filesize($filename);
		$id = $this->insertfiledata($name,$type,$size);
		return $id;
	}	
	# insert file information into system table
	public function insertfiledata($name, $type, $size,$source=null){
		$name=$this->core->escapeString($name);
		$fileid=$this->core->dbo->insert($this->filestable,array(
			"name" => $name,
			"type" => $type,
			"size" => (int) $size,
			"source"=>( $source!=null)?$source:($this->core->getenvlayer()==_ENV_KERNEL?"kernel":$this->core->getenvcaller("mod")),
			"cdate" => date("Y-m-d H:i:s")
		),"id");
		return $fileid;
	}	
    # file extension
	public function parseextension($name){
		$data = explode(".", $name);
		return (count($data) == 0 || !is_array($data)) ? null : $data[count($data) - 1];
	}
    # filename from database
	public function filenamebyid($id){
		$name = $this->core->dbo->select($this->filestable, "name", "where id='".(int)$id."' limit 1 offset 0",_RESULT_SINGLE);
		return (!$name)?false:$name;
	}
    # file delete
	public function delete($id){
		$name= $this->core->dbo->select($this->filestable, "name", "where id='" . $this->core->escapeString($id) . "' limit 1 offset 0",_RESULT_SINGLE);
		if($name==null)
			return true;
		$filename = $this->core->parseasdir($this->core->get("uploadsdir")).$name;
		if( file_exists($filename)){
			unlink($filename);
		}
		$this->core->dbo->delete($this->filestable, " where id='" . $id . "' ");
		return true;
	}
	# get all files in directory
	public function getdirfiles($dir,$match=null){
		$files = array();
		if( $d = opendir($dir)){
			while (false !== ($file = readdir($d))) {
			if ($file != "." && $file != "..") {
				if( $match!=null){
					if( !preg_match($match,$file)){
						continue;
					}
				}
				$files[]=$file;				
			}
		}
		}
		closedir($d);
		return $files;
	}
	# recursively directory coping
	public function copydir($src,$dst) {
		$dir = opendir($src);
    	if( !is_dir($dst))
    		mkdir($dst);
    	while(false !== ( $file = readdir($dir)) ) {
        	if (( $file != '.' ) && ( $file != '..' )) {
            	if ( is_dir($src.'/'.$file) ) {
                	$this->copydir($src . '/' . $file,$dst . '/' . $file);
            	} else {
            		copy($src.'/'.$file,$dst.'/'.$file);
           		}
        	}
    	}
    	closedir($dir);
	}
	# removing directory with all data
    public function deletedir($dir) {
        if (!file_exists($dir)) return true;
        if (!is_dir($dir)) return unlink($dir);
        foreach (scandir($dir) as $item) {
            if ($item == '.' || $item == '..') continue;
            if (!$this->deletedir($dir.DIRECTORY_SEPARATOR.$item)) return false;
        }
        return rmdir($dir);
    }
}
?>